/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package dp1.titandevelop.titano.helper;

import dp1.titandevelop.titano.bean.EmpleadoSeleccionado;
import dp1.titandevelop.titano.bean.Movimiento;
import dp1.titandevelop.titano.bean.galletaAux;
import dp1.titandevelop.titano.bean.mermaAux;
import dp1.titandevelop.titano.persistent.Empleado;
import dp1.titandevelop.titano.persistent.EmpleadoXProcesoTurno;
import dp1.titandevelop.titano.persistent.Proceso;
import dp1.titandevelop.titano.persistent.Producto;
import dp1.titandevelop.titano.persistent.ProductoXProceso;
import dp1.titandevelop.titano.persistent.Receta;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Random;


/**

 * @author naty
 */
public class HelperAlgoritmo {
    /*Constantes generales*/
    public static final int SALIDA=1;//1;
    public static final int ENTRADA=0;//2;
    /*Constantes Grasp*/
    public static final int NUMITERACIONGRASP = 5000;
    public static final float ALPHA=0.4f;//0.4
    /*Constantes Tabu*/
    public static final int NUMITERACIONTABU=1200;
    public static final int NUMITERACIONTABU2=10;
    public static final int TAMVECINDAD=9;
    public static final int TENENCIA=7;
   
   /*Variables*/
    private ArrayList<galletaAux> galletas;
    private ArrayList<ProductoXProceso> productoProcesoSalida;
    private ArrayList<EmpleadoSeleccionado> solucionGrasp;
    private ArrayList<Receta> listaReceta;
      
    
        

    private int hallarCantidad(ArrayList<EmpleadoXProcesoTurno> listaOperario) {
        ArrayList<Empleado> e=new ArrayList();
        for(int i=0;i<listaOperario.size();i++ ) {
            if(!esta(listaOperario.get(i),e)){
                e.add(listaOperario.get(i).getToEmpleado());
            }
        } 
        
        return e.size();
    }
    
    private boolean esta(EmpleadoXProcesoTurno lo,ArrayList<Empleado> e){
        for(int i=0;i<e.size();i++){
           if(lo.getToEmpleado().getIdempleado().equals(e.get(i).getIdempleado())){
               return true;
           }
        }
        return false;
    
    }

    private ArrayList<Proceso> hallarProcesos(ArrayList<ProductoXProceso> procesosTotales) {
       ArrayList<Proceso> aux= new ArrayList();
   
       for(int i=0;i<procesosTotales.size();i++){
           if(!estaProceso(procesosTotales.get(i).getToProceso(),aux)){
               Proceso p=new Proceso();
               p.setCantidadmaquina(procesosTotales.get(i).getToProceso().getCantidadmaquina());
               p.setCapacidadmaquina(procesosTotales.get(i).getToProceso().getCapacidadmaquina());
               p.setEstado(procesosTotales.get(i).getToProceso().getEstado());
               p.setDescripcion(procesosTotales.get(i).getToProceso().getDescripcion());
               p.setIdproceso(procesosTotales.get(i).getToProceso().getIdproceso());
               p.setToZona(null);
               aux.add(p);
            }
       }
       
       return aux;
       
    }
    
    private boolean estaProceso(Proceso p, ArrayList<Proceso> aux){
        for(int i=0;i<aux.size();i++){
            if(p.getIdproceso().equals(aux.get(i).getIdproceso())){
                return true;
            }
        }
        return false;
    }



    
    public class HiloGrasp extends Thread {
    private ArrayList<EmpleadoXProcesoTurno> le;
    private ArrayList<mermaAux> m;
    private int cantidad;
    private int h;
    private ArrayList<EmpleadoSeleccionado> solucion=new ArrayList();
    private ArrayList<EmpleadoSeleccionado> solucionConstruccion;
    
        HiloGrasp(ArrayList<EmpleadoXProcesoTurno> listaEmpleadoProceso, ArrayList<mermaAux> mermasProceso, int c,int x) {
            cantidad=c;
            le=listaEmpleadoProceso;
            m=mermasProceso;
            h=x;
        }
    
    @Override
         public void run() {
             while(cantidad>0) {
             solucionConstruccion=faseConstruccion(le,galletas,productoProcesoSalida,m);
             solucion=mejorSolucion(solucion,solucionConstruccion);
             cantidad--;       
            }
            solucionGrasp=mejorSolucionGrasp(solucion);
         }
    }
    
    
    public ArrayList<EmpleadoSeleccionado> tabuSearch(ArrayList<EmpleadoSeleccionado> solucionInicial,ArrayList<EmpleadoXProcesoTurno>listaEmpleadoProceso){
            
        ArrayList<EmpleadoSeleccionado> solucionActual=new ArrayList();
        ArrayList<EmpleadoSeleccionado> mejorVecino;
   
        
        for(int i=0;i<galletas.size();i++){
            ArrayList<EmpleadoSeleccionado> listaInicial= obtenerSolucionPorGalleta(solucionInicial,galletas.get(i).getGalleta().getIdproducto());
            ArrayList<EmpleadoSeleccionado> solucionParcial=new ArrayList(listaInicial);
            ArrayList<Movimiento> lista_tabu = new ArrayList();
            int numIteracion = NUMITERACIONTABU;
            int numIterRepeticion = 0;
        
            if(!listaInicial.isEmpty() && listaInicial.size()!=1){
                while ( numIteracion > 0 ) {
                numIteracion--;

                if ( numIterRepeticion == NUMITERACIONTABU2 ) break;

                /* Generar los vecinos*/
                double maxMov=0;
                int indiceMax = 0;
                ArrayList<Movimiento> listaMovimiento = new ArrayList();

                for (int j=0; j<TAMVECINDAD; j++) {
                    Movimiento movimiento = generarMovimiento(listaInicial,listaEmpleadoProceso,galletas.get(i).getGalleta().getIdproducto());
                    listaMovimiento.add(movimiento);
                    if(j==0){
                        maxMov=movimiento.getValorMovimiento();
                        indiceMax=j;
                    }

                    if (maxMov < movimiento.getValorMovimiento() ) { 
                        maxMov = movimiento.getValorMovimiento();
                        indiceMax = j;
                    }
                }    


                if ( !this.esTabuActivo(listaMovimiento.get(indiceMax), lista_tabu) ) {

                    listaMovimiento.get(indiceMax).setTenencia(TENENCIA);
                    lista_tabu.add(listaMovimiento.get(indiceMax));

                    mejorVecino = intercambio(listaMovimiento.get(indiceMax), listaInicial,listaEmpleadoProceso,galletas.get(i).getGalleta().getIdproducto());
                    listaInicial=new ArrayList(mejorVecino);

                    if ( sumatoriaFuncionObjetivo(solucionParcial) < sumatoriaFuncionObjetivo(mejorVecino) ) {
                        solucionParcial = mejorVecino;
                        numIterRepeticion=0;
                    } else {
                        numIterRepeticion++;
                    }
                } else {
                // aca va el criterio de aspiracion
                    continue;
                } 

                    for (int n=0; n<lista_tabu.size(); n++ ) {
                        if ( lista_tabu.get(n).getTenencia() == 0 )
                            lista_tabu.remove(n);
                        lista_tabu.get(n).setTenencia(lista_tabu.get(n).getTenencia() -1);

                    }

                }
                
            }
                solucionActual.addAll(solucionParcial);
                
        
        }
   
        return solucionActual;    
        
    }
    
    public ArrayList<EmpleadoSeleccionado> grasp(ArrayList<EmpleadoXProcesoTurno>listaEmpleadoProceso,ArrayList<Proceso> listaProceso,ArrayList<galletaAux>galleta, ArrayList<ProductoXProceso> procesoProductoSalida,ArrayList<Receta> recetas) throws InterruptedException{
    solucionGrasp=new ArrayList();
    //ArrayList<EmpleadoSeleccionado>solucionConstruccion=new ArrayList();
    //ArrayList<EmpleadoSeleccionado> solucion=new ArrayList();
      
    /*Datos de galletas*/
    galletas=galleta;
    productoProcesoSalida=procesoProductoSalida;
    listaReceta=recetas;
  
    
  
    /*Datos de merma*/
    ArrayList<mermaAux> mermasProceso=hallarMermaProcesos();    
    
    /*Retorna la cantidad de core que tiene la maquina virtual de java*/
    int numeroProcesadores=Runtime.getRuntime().availableProcessors();
    int numeroIteraciones=NUMITERACIONGRASP/numeroProcesadores;
//    int numeroIteraciones=NUMITERACIONGRASP;
   
             
    
   HiloGrasp [] hiloPrueba = new HiloGrasp[numeroProcesadores];
   for(int i=0;i<numeroProcesadores;i++){ 
       hiloPrueba[i] = new HiloGrasp(listaEmpleadoProceso,mermasProceso, numeroIteraciones,i);
       hiloPrueba[i].start(); 
   }
   
             
   for( int i = 0; i < numeroProcesadores; i++){ 
       try{ 
           hiloPrueba[i].join();
       }catch(InterruptedException e){
       }
   }
    
//    while(numeroIteraciones>0) {
//             solucionConstruccion=faseConstruccion(listaEmpleadoProceso,galletas,productoProcesoSalida,mermasProceso);
//             solucion=mejorSolucion(solucion,solucionConstruccion);
//             numeroIteraciones--;       
//            }
    return solucionGrasp;
    //return solucion;
}
    
    
    //Funciones Generales
    private double sumatoriaFuncionObjetivo(ArrayList<EmpleadoSeleccionado> listaActual) {
        double acumulado=0;
 
        for (int i=0; i<listaActual.size(); i++) {
            if(listaActual.get(i).getEmpleadoProceso().getToProceso().getIdproceso()==4)
            acumulado += (2*listaActual.get(i).getFo()) ;
            else
            acumulado += listaActual.get(i).getFo() ;
        }
        return acumulado;
    }
     
    private double funcionObjetivo(EmpleadoXProcesoTurno elemento,int idProceso,int idGalleta) {
        double valor;
        
        if(elemento.getRotura()==0 && elemento.getProductividad()==0){
            return 0;
        }else if (elemento.getProductividad()==0 && elemento.getRotura()!=0){
            return -1;
        }else if (elemento.getProductividad()!=0 && elemento.getRotura()==0){
            valor= elemento.getProductividad()*hallarCosto(idProceso,idGalleta,elemento.getRotura(),elemento.getProductividad());
            return valor;
        }else{               
            valor= (elemento.getProductividad()/elemento.getRotura())* hallarCosto(idProceso,idGalleta,elemento.getRotura(),elemento.getProductividad());
            return valor;
        }
    }
    
    public  double hallarCosto(int idProceso, int idGalleta,double empleadoRotura,double empleadoProductividad) {
        double beneficio=0;
        double costo=0;
        for(int i=0;i< productoProcesoSalida.size();i++){
            if(productoProcesoSalida.get(i).getToProducto().getIdproducto()==idGalleta &&
                    productoProcesoSalida.get(i).getToProceso().getIdproceso()== idProceso){
                        beneficio=productoProcesoSalida.get(i).getToProducto1().getBeneficio(); 
                        costo=productoProcesoSalida.get(i).getToProducto1().getCosto(); 
            }
        }      
        return (empleadoProductividad*beneficio)-(empleadoRotura*costo);
                
    }
    
    public  void hallarCostoBeneficio(EmpleadoSeleccionado e,int idProceso, int idGalleta) {
        double beneficio=0;
        double costo=0;
        for(int i=0;i< productoProcesoSalida.size();i++){
            if(productoProcesoSalida.get(i).getToProducto().getIdproducto()==idGalleta &&
                    productoProcesoSalida.get(i).getToProceso().getIdproceso()== idProceso){
                        beneficio=productoProcesoSalida.get(i).getToProducto1().getBeneficio(); 
                        costo=productoProcesoSalida.get(i).getToProducto1().getCosto(); 
            }
        }      
       e.setBeneficio(beneficio*e.getEmpleadoProceso().getProductividad());
       e.setCosto(costo*e.getEmpleadoProceso().getRotura()); 
                
    }
    
    
    
    //Funciones Tabu
    private Movimiento generarMovimiento(ArrayList<EmpleadoSeleccionado> listaInicial,ArrayList<EmpleadoXProcesoTurno>listaEmpleadoProceso,int idProducto) {
        Movimiento movimiento = new Movimiento();
        
        
        Random rn = new Random();
        int n = listaInicial.size();
        int i = rn.nextInt() % n;

       
        int indiceEmpleado1= Math.abs(i);
        int indiceEmpleado2 = indiceEmpleado1;
        
        while ( indiceEmpleado1 == indiceEmpleado2 ) {
            i = rn.nextInt() % n;
            indiceEmpleado2 = Math.abs(i);
        }
        
        
        movimiento.setIdEmpleado1(listaInicial.get(indiceEmpleado1).getEmpleadoProceso());
        movimiento.setIndiceEmpleado1(indiceEmpleado1);
        movimiento.setIdEmpleado2(listaInicial.get(indiceEmpleado2).getEmpleadoProceso());
        movimiento.setIndiceEmpleado2(indiceEmpleado2);
        
        ArrayList<EmpleadoSeleccionado> listaActual= intercambio(movimiento, listaInicial,listaEmpleadoProceso,idProducto);
        
        double valorMovimiento = hallarValorMovimiento(listaInicial,listaActual);
        movimiento.setValorMovimiento(valorMovimiento);
        
        return movimiento;
    }
  
    public double hallarValorMovimiento(ArrayList<EmpleadoSeleccionado> lista1, ArrayList<EmpleadoSeleccionado> lista2) {
     double s1 = this.sumatoriaFuncionObjetivo(lista1);
     double s2 = this.sumatoriaFuncionObjetivo(lista2);
    
     return s2 - s1;
    }

    private boolean esTabuActivo(Movimiento movimiento, ArrayList<Movimiento> lista_tabu) {
        for (int i=0; i<lista_tabu.size(); i++) {
            if ((movimiento.getIdEmpleado1()== lista_tabu.get(i).getIdEmpleado1() && movimiento.getIdEmpleado2() == lista_tabu.get(i).getIdEmpleado2())
                || movimiento.getIdEmpleado2()== lista_tabu.get(i).getIdEmpleado1() && movimiento.getIdEmpleado1() == lista_tabu.get(i).getIdEmpleado2() )
                return true;
        }
        return false;
    }

    private ArrayList<EmpleadoSeleccionado> intercambio(Movimiento movimiento, ArrayList<EmpleadoSeleccionado> listaInicial,ArrayList<EmpleadoXProcesoTurno>listaEmpleadoProceso,int idProducto) {
        EmpleadoXProcesoTurno elem1=movimiento.getIdEmpleado1();
        EmpleadoXProcesoTurno elem2=movimiento.getIdEmpleado2();
        EmpleadoXProcesoTurno nuevoElem1=null;
        EmpleadoXProcesoTurno nuevoElem2=null;
        
        ArrayList<EmpleadoSeleccionado> listaIntercambio = new ArrayList<EmpleadoSeleccionado>(listaInicial);
        if(movimiento.getIndiceEmpleado1() > movimiento.getIndiceEmpleado2()){
            listaIntercambio.remove(movimiento.getIndiceEmpleado1());
            listaIntercambio.remove(movimiento.getIndiceEmpleado2());
        }else{
            listaIntercambio.remove(movimiento.getIndiceEmpleado2());
            listaIntercambio.remove(movimiento.getIndiceEmpleado1());
        }
                
        for (int i=0; i<listaEmpleadoProceso.size(); i++) {
            if (listaEmpleadoProceso.get(i).getToEmpleado().getIdempleado() == elem1.getToEmpleado().getIdempleado()
                    && listaEmpleadoProceso.get(i).getToProceso().getIdproceso()==elem2.getToProceso().getIdproceso()) {
                nuevoElem1 = listaEmpleadoProceso.get(i);
                nuevoElem1.setFo((float)funcionObjetivo(nuevoElem1,nuevoElem1.getToProceso().getIdproceso(),idProducto));
        
            } else if (listaEmpleadoProceso.get(i).getToEmpleado().getIdempleado() == elem2.getToEmpleado().getIdempleado()
                    && listaEmpleadoProceso.get(i).getToProceso().getIdproceso()==elem1.getToProceso().getIdproceso()  ) {
                nuevoElem2 = listaEmpleadoProceso.get(i);
                nuevoElem2.setFo((float)funcionObjetivo(nuevoElem2,nuevoElem2.getToProceso().getIdproceso(),idProducto));
            }
            if(nuevoElem1!=null && nuevoElem2!=null){
                break;
            }
            
        }
                
        EmpleadoSeleccionado empleadoSeleccionado1= new EmpleadoSeleccionado();
        EmpleadoSeleccionado empleadoSeleccionado2=new EmpleadoSeleccionado();
        
        if(nuevoElem1!=null && nuevoElem2!=null){
            empleadoSeleccionado1.setEmpleadoProceso(nuevoElem1);
            empleadoSeleccionado1.setGalleta(idProducto);
            empleadoSeleccionado1.setFo(nuevoElem1.getFo());
            hallarCostoBeneficio(empleadoSeleccionado1,empleadoSeleccionado1.getEmpleadoProceso().getToProceso().getIdproceso(),empleadoSeleccionado1.getGalleta());
            empleadoSeleccionado2.setEmpleadoProceso(nuevoElem2);
            empleadoSeleccionado2.setGalleta(idProducto);
            empleadoSeleccionado2.setFo(nuevoElem2.getFo());
            hallarCostoBeneficio(empleadoSeleccionado2,empleadoSeleccionado2.getEmpleadoProceso().getToProceso().getIdproceso(),empleadoSeleccionado2.getGalleta());
        }
        
        listaIntercambio.add(empleadoSeleccionado1);
        listaIntercambio.add(empleadoSeleccionado2);
        
        return listaIntercambio;  
    }  
    
    private ArrayList<EmpleadoSeleccionado> obtenerSolucionPorGalleta(ArrayList<EmpleadoSeleccionado> solucionInicial, int idProducto) {
      ArrayList<EmpleadoSeleccionado> seleccionados= new ArrayList();
        for(int i=0; i< solucionInicial.size() ;i++){
          if(solucionInicial.get(i).getGalleta()==idProducto){
              seleccionados.add(solucionInicial.get(i));
          }
        }
        
        return seleccionados;
    }
    
    /*Funciones para el Algoritmo GRASP*/
    private ArrayList<EmpleadoSeleccionado> faseConstruccion(ArrayList<EmpleadoXProcesoTurno>listaEmpleadoProceso,ArrayList<galletaAux>galletas,ArrayList<ProductoXProceso>productoProceso,ArrayList<mermaAux> mermasProceso) {
        ArrayList<EmpleadoXProcesoTurno> listaOperario= new ArrayList(listaEmpleadoProceso);
        ArrayList<Empleado> empleadoAsignados=new ArrayList();
        int cantidadEmpleados=hallarCantidad(listaOperario);
        ArrayList<EmpleadoSeleccionado> solucionConst=new ArrayList();
        ArrayList<ProductoXProceso> procesosTotales=new ArrayList(productoProceso);
        ArrayList<Proceso> procesosUsados= hallarProcesos(procesosTotales);
        EmpleadoXProcesoTurno nuevoElemento;
        int indiceElemento;
        Random rnd = new Random();
        
        
        /*Se itera por galletas*/
        for(int p=0;p<galletas.size();p++){
            /*Busca los procesos que existen por el producto a elegir*/
            ArrayList<Proceso> procesosSalida=obtenerProceso(galletas.get(p).getGalleta(),procesosTotales);
            
            if(!procesosSalida.isEmpty()){
            /*Obtener Demanda Por Galleta*/
            int demandaGalleta=galletas.get(p).getDemanda();
            float a=buscarMerma(mermasProceso,procesosSalida);
            int adicional=Math.round(a*demandaGalleta);
            int demandaTotal=(demandaGalleta + adicional);
            
            /*Total producido*/
            int producidoTotal=0;
            boolean salir=false;
                    
            /*Empiezo la construcción*/  
            while(producidoTotal< demandaTotal && !salir && cantidadEmpleados>empleadoAsignados.size() && maquinadisponibles(procesosUsados)){
            salir=false;    
            ArrayList<EmpleadoSeleccionado> SolucionParcial= new ArrayList();
            
            /*Inicializar el orden de cada galleta*/
            int ordenGalleta=0;
            
            /*Verificar que cumpla todo el flujo*/
            //boolean flujoCompleto=true;
            
           
            /*Comienza iteracion por proceso*/
            for(int i=0; i< procesosSalida.size();i++){    
                try{     
                /*Verificar disponibilidad de horarios y maquinas*/
                if(cantidadEmpleados>empleadoAsignados.size() && disponible(procesosUsados,procesosSalida.get(i).getIdproceso())){
                    Boolean entro=true;
                        /*Verifica que se ejecuten  orden los procesos*/
                        if(ordenGalleta+1==obtenerOrden(galletas.get(p).getGalleta().getIdproducto(),procesosSalida.get(i).getIdproceso(),productoProceso)){
                            
                            /*Total de Operario por turno*/
                            ArrayList<EmpleadoXProcesoTurno> OperarioMaquina;
                            OperarioMaquina=obtenerOperariosProceso(listaOperario,procesosSalida.get(i).getIdproceso(),empleadoAsignados);

                            /*Se halla la funcion objetivo para los miembros a evaluar*/     
                            for(int j=0;j<OperarioMaquina.size();j++){
                                OperarioMaquina.get(j).setFo((float)funcionObjetivo(OperarioMaquina.get(j),procesosSalida.get(i).getIdproceso(),galletas.get(p).getGalleta().getIdproducto()));
                           }
                            

                            ArrayList<EmpleadoXProcesoTurno> RCL=new ArrayList();
                            if(!OperarioMaquina.isEmpty()){
                            float mejor= hallarMejor(OperarioMaquina);
                            float peor = hallarPeor(OperarioMaquina);
                            
                            /*Llena el RCL*/
                           
                            for(int j=0; j<OperarioMaquina.size();j++){
                                if((OperarioMaquina.get(j).getFo()>=(mejor-ALPHA*(mejor-peor))) && (OperarioMaquina.get(j).getFo() <=mejor) ){        
                                   RCL.add(OperarioMaquina.get(j));
                                }
                            }
                            
                            indiceElemento = rnd.nextInt(RCL.size());
                            nuevoElemento = RCL.get(indiceElemento);                

                            EmpleadoSeleccionado nuevoFinal= new EmpleadoSeleccionado(nuevoElemento,galletas.get(p).getGalleta().getIdproducto());
                            nuevoFinal.setFo(nuevoElemento.getFo());
                            nuevoFinal.getEmpleadoProceso().getToEmpleado().setAsignado(true);                   
                            hallarCostoBeneficio(nuevoFinal,nuevoFinal.getEmpleadoProceso().getToProceso().getIdproceso(),nuevoFinal.getGalleta());                            
                            SolucionParcial.add(nuevoFinal);
                            entro=false;
                            empleadoAsignados=asignarEmpleado(nuevoFinal.getEmpleadoProceso().getToEmpleado(),empleadoAsignados);
                            procesosUsados=actualizarCantidadMaquina(procesosUsados,procesosSalida.get(i).getIdproceso());

                          }
                   } //Fin del if de orden
                        
                   if(!entro){
                        ordenGalleta++;
                    }else{
                      //  flujoCompleto=false;
                    }

                } //Fin de if si hay personas o maquinas
              }catch(IllegalArgumentException e){
              
              }
               
            }//Fin del for de proceso
                
                //if(flujoCompleto){
                    producidoTotal=(int)cantidadMateriaProceso(SolucionParcial,4);
                    demandaTotal=demandaTotal-producidoTotal;
                    solucionConst.addAll(SolucionParcial);
                    if(producidoTotal==0){salir=true;}
                //}
                
            }//Fin del while
       
           }//Fin del if proceso
            
        }//End for Galleta
        
        return solucionConst;
 
    }
    
    /*Halla la mejor solucion para la construccion de RCL*/    
    private float hallarMejor(ArrayList<EmpleadoXProcesoTurno> listaCandidatos) {
        float mejor=listaCandidatos.get(0).getFo();
        float aux;
        
        for(int i=0; i< listaCandidatos.size();i++){
            aux=listaCandidatos.get(i).getFo();
            if(aux>mejor) {
                mejor=aux;
            }     
        }
        return mejor;
    }

    /*Halla la peor solucion para la construccion de RCL*/
    private float hallarPeor(ArrayList<EmpleadoXProcesoTurno> listaCandidatos) {
        float peor=listaCandidatos.get(0).getFo();
        float aux;
        
        for(int i=0; i< listaCandidatos.size();i++){
            aux=listaCandidatos.get(i).getFo();
            if(aux<peor) {
                peor=aux;
            }     
        }
        return peor;
    }
   
    /*Verificar si es factible, si ya no ha sido seleccionado antes*/
    private boolean esFactible(EmpleadoXProcesoTurno nuevoElemento, ArrayList<Empleado>listaEmpleado) {
        
        for(int i=0;i<listaEmpleado.size();i++){
            if(nuevoElemento.getToEmpleado().getIdempleado().equals(listaEmpleado.get(i).getIdempleado())){
                return false;
            }
        }
        
        return true;
    }
        
    private ArrayList<Proceso> obtenerProceso(Producto producto, ArrayList<ProductoXProceso> productoProceso) {
        ArrayList<Proceso> listProceso= new ArrayList();
        ArrayList<ProductoXProceso> aux=new ArrayList();
        
        for(int i=0;i <productoProceso.size();i++){
            int idProducto1=productoProceso.get(i).getToProducto().getIdproducto();
            int idProducto2=producto.getIdproducto();
            if(idProducto1== idProducto2 && productoProceso.get(i).getTipomovimiento()==SALIDA){
                aux.add(productoProceso.get(i));
            }
        }
        
        //Odenar Por Orden
        Comparator comparador = new Comparator<ProductoXProceso>() {
            @Override
            public int compare(ProductoXProceso e1, ProductoXProceso e2) {
                if (e1.getOrden() <= e2.getOrden()) {
                    return -1;
                } 
                if (e1.getOrden() > e2.getOrden()) {
                    return +1;
                } 
                return 1;
            }
        };
        
        /* Ordena por un quicksort*/
        Collections.sort(aux, comparador);
        
        for(int j=0;j<aux.size();j++){
            listProceso.add(aux.get(j).getToProceso());
        }
        
        
        return listProceso;
    }
   
    private ArrayList<EmpleadoXProcesoTurno> obtenerOperariosProceso(ArrayList<EmpleadoXProcesoTurno> OperarioMaquina, int idProceso,ArrayList<Empleado> listaEmpleado) {
        ArrayList<EmpleadoXProcesoTurno> aux=new ArrayList();
        
        for(int i=0; i< OperarioMaquina.size();i++){
            if(OperarioMaquina.get(i).getToProceso().getIdproceso().equals(idProceso) && esFactible(OperarioMaquina.get(i),listaEmpleado)){
               aux.add(OperarioMaquina.get(i));
            }
            
        }
        return aux;
    }

    private ArrayList<mermaAux> hallarMermaProcesos() {
        ArrayList<mermaAux> aux=new ArrayList();
        ArrayList<Proceso> procesos=dp1.titandevelop.titano.service.ProcesoService.buscar();
        
        for(int i=0;i< procesos.size();i++){
            mermaAux auxmerma=new mermaAux();
            auxmerma.setIdProceso(procesos.get(i).getIdproceso());
            auxmerma.setPorcentajeMerma(hallarPorcentajeMerma(procesos.get(i).getIdproceso()));
            aux.add(auxmerma);
        }
        
        return aux;
    }
    
    private float hallarPorcentajeMerma(int idProceso) {
        ArrayList<EmpleadoXProcesoTurno> produccion=dp1.titandevelop.titano.service.EmpleadoXProcesoTurnoService.buscarPorIdProceso(idProceso);
        float suma=0;
        
        for(int i=0;i<produccion.size();i++){
            suma+=produccion.get(i).getRotura()/(produccion.get(i).getProductividad()+produccion.get(i).getRotura());
        }
        suma=suma/produccion.size();
        return suma;
    }
    
    private float buscarMerma(ArrayList<mermaAux> mermasProceso,ArrayList<Proceso> procesos) {
        float suma=0;
        
        for(int k=0;k<procesos.size();k++){
            for(int i=0;i<mermasProceso.size();i++){
                if(mermasProceso.get(i).getIdProceso()==procesos.get(k).getIdproceso())
                    suma+= mermasProceso.get(i).getPorcentajeMerma();
            }
        }
        if(!procesos.isEmpty()){
            return suma/procesos.size();
        }else{
            return 0;
        }
    }
    
    private ArrayList<Empleado> asignarEmpleado(Empleado e, ArrayList<Empleado> listaEmpleado) {
        Empleado aux=new Empleado();
        
        aux.setApellidom(e.getApellidom());
        aux.setApellidop(e.getApellidop());
        aux.setAsignado(Boolean.TRUE);
        aux.setCelular(e.getCelular());
        aux.setDireccion(e.getDireccion());
        aux.setDni(e.getDni());
        aux.setEmail(e.getEmail());
        aux.setEstado(e.getEstado());
        aux.setFechanacimiento(e.getFechanacimiento());
        aux.setIdempleado(e.getIdempleado());
        aux.setSexo(e.getSexo());
        listaEmpleado.add(aux);
        return listaEmpleado;
        }
   
    private ArrayList<EmpleadoSeleccionado> mejorSolucion(ArrayList<EmpleadoSeleccionado> solucion, ArrayList<EmpleadoSeleccionado> solucionConstruccion) {
        double valorFO_solucion=0;
        double valorFO_construccion=0;
        //double valorMerma_solucion=0;
        //double valorMerma_construccion=0;
        //double varianza_solucion=0;
        //double varianza_construccion=0;
        //double media_solucion=0;
        //double media_construccion=0;
        
        //Evaluacion de la funcion Objetivo
        valorFO_solucion=sumatoriaFuncionObjetivo(solucion);
        valorFO_construccion=sumatoriaFuncionObjetivo(solucionConstruccion);

        
        //Desviacion standar de acuerdo a la merma
        //media_solucion=valorMerma_solucion/solucion.size();
        //media_construccion=valorMerma_construccion/solucionConstrucion.size();
        
        //for(int i=0;i<solucion.size();i++){
          //  varianza_solucion+=Math.pow((solucion.get(i).getMerma()-media_solucion),2);
        //}
        //for(int j=0;j<solucion.size();j++){
          //  varianza_construccion+=Math.pow((solucion.get(j).getMerma()-media_solucion),2);
        //}
        
        //varianza_solucion=Math.sqrt(varianza_solucion/solucion.size()-1);
        //varianza_solucion=Math.sqrt(varianza_construccion/solucionConstrucion.size()-1);
        
        
        if(valorFO_solucion>valorFO_construccion){
            return solucion;
        }else{
            return solucionConstruccion;
        }
    }
    
    private synchronized ArrayList<EmpleadoSeleccionado> mejorSolucionGrasp(ArrayList<EmpleadoSeleccionado> solucionConstruccion) {
        double valorFO_solucion=0;
        double valorFO_construccion=0;
        //double valorMerma_solucion=0;
        //double valorMerma_construccion=0;
        //double varianza_solucion=0;
        //double varianza_construccion=0;
        //double media_solucion=0;
        //double media_construccion=0;
        
        //Evaluacion de la funcion Objetivo
        valorFO_solucion=sumatoriaFuncionObjetivo(solucionGrasp);
        valorFO_construccion=sumatoriaFuncionObjetivo(solucionConstruccion);

        
        //Desviacion standar de acuerdo a la merma
        //media_solucion=valorMerma_solucion/solucion.size();
        //media_construccion=valorMerma_construccion/solucionConstrucion.size();
        
        //for(int i=0;i<solucion.size();i++){
          //  varianza_solucion+=Math.pow((solucion.get(i).getMerma()-media_solucion),2);
        //}
        //for(int j=0;j<solucion.size();j++){
          //  varianza_construccion+=Math.pow((solucion.get(j).getMerma()-media_solucion),2);
        //}
        
        //varianza_solucion=Math.sqrt(varianza_solucion/solucion.size()-1);
        //varianza_solucion=Math.sqrt(varianza_construccion/solucionConstrucion.size()-1);
        
        
        if(valorFO_solucion>valorFO_construccion){
            return solucionGrasp;
        }else{
            return solucionConstruccion;
        }
    }

    private int obtenerOrden(int idproducto, int idproceso, ArrayList<ProductoXProceso> productoProceso) {
        for(int i=0;i<productoProceso.size();i++){
            if(productoProceso.get(i).getToProducto().getIdproducto()==idproducto &&
                   productoProceso.get(i).getToProceso().getIdproceso()==idproceso &&
                    productoProceso.get(i).getTipomovimiento()==SALIDA){
                return productoProceso.get(i).getOrden();
            }
        }
        return 0;
    }

    private boolean maquinadisponibles(ArrayList<Proceso> procesos) {
        int cantidad=0;
        for(int i=0;i<procesos.size();i++){
            if(procesos.get(i).getCantidadmaquina()<1){
                cantidad++;
            }
        }
        
        if(cantidad==procesos.size()){
            return false;
        }else{
            return true;
        }
    }

    private boolean disponible(ArrayList<Proceso> p,int idProceso) {
       
        for(int i=0;i<p.size();i++){
            if(p.get(i).getIdproceso()==idProceso){
               return p.get(i).getCantidadmaquina()>0;
            }
       }
        
        return false;
    }

    private ArrayList<Proceso> actualizarCantidadMaquina(ArrayList<Proceso> procesosTotales, int idproceso) {
        
        for(int i=0;i<procesosTotales.size();i++){
            if(procesosTotales.get(i).getIdproceso()== idproceso){
                procesosTotales.get(i).setCantidadmaquina(procesosTotales.get(i).getCantidadmaquina()-1);
            }
        }
        return procesosTotales;
    }

    

    public ArrayList<EmpleadoSeleccionado> completarProductosIntermedios(ArrayList<EmpleadoSeleccionado> solucion, ArrayList<EmpleadoXProcesoTurno> listaEmpleadoTurno) {
        ArrayList<EmpleadoSeleccionado> solucionGalleta=new ArrayList();
        ArrayList<EmpleadoSeleccionado> solucionFinal=new ArrayList();
        ArrayList<Proceso> procesosUsados= hallarProcesos(productoProcesoSalida);
        actualizarCantidadProcesos(procesosUsados,solucion);
        ArrayList<EmpleadoSeleccionado> empleadoAsignados=new ArrayList();

        
        for(int i=0;i<galletas.size();i++){
            solucionGalleta=this.obtenerSolucionPorGalleta(solucion, galletas.get(i).getGalleta().getIdproducto());
            ArrayList<Proceso> listaProceso=this.obtenerProceso(galletas.get(i).getGalleta(), productoProcesoSalida);
            float cantidadGalletas=cantidadMateriaProceso(solucionGalleta,4);
            for(int j=0;j<listaProceso.size();j++){
                if(listaProceso.get(j).getIdproceso()!=4){
                ArrayList<EmpleadoXProcesoTurno> empleadoDisponiblePorProceso=obtenerOperarios(listaEmpleadoTurno,listaProceso.get(j).getIdproceso(),solucion,empleadoAsignados);
                float cantidadTotalMp=cantidadMateriaProceso(solucionGalleta,listaProceso.get(j).getIdproceso());
                Producto pmaterial= hallarProductoIntermedio(listaProceso.get(j).getIdproceso(),galletas.get(i).getGalleta().getIdproducto());
                float cantidadMp=hallarCantidadMateriaPrima(galletas.get(i).getGalleta().getIdproducto(),pmaterial.getIdproducto());
                
                int demanda= (int) (cantidadGalletas- Math.round(cantidadTotalMp/cantidadMp));
                
                solucionGalleta=asignarVoraz(empleadoDisponiblePorProceso,solucionGalleta,demanda,galletas.get(i).getGalleta().getIdproducto(),listaProceso.get(j).getIdproceso(),procesosUsados,empleadoAsignados);
                }
                                      
            }
            solucionFinal.addAll(solucionGalleta);
        }
        return solucionFinal;
    }
    
    private ArrayList<EmpleadoSeleccionado> asignarVoraz(ArrayList<EmpleadoXProcesoTurno> empleadoDisponiblePorProceso, ArrayList<EmpleadoSeleccionado> solucionGalleta, int demanda,int idGalleta,int idProceso, ArrayList<Proceso> procesoUsados,ArrayList<EmpleadoSeleccionado>empleadoAsignados) {
        
        //Odenar Por Orden
        Comparator comparador = new Comparator<EmpleadoXProcesoTurno>() {
            @Override
            public int compare(EmpleadoXProcesoTurno e1, EmpleadoXProcesoTurno e2) {
                if (e1.getProductividad() >= e2.getProductividad()) {
                    return -1;
                } 
                if (e1.getProductividad() < e2.getProductividad()) {
                    return +1;
                } 
                return 1;
            }
        };
        
        /* Ordena por un quicksort*/
        Collections.sort(empleadoDisponiblePorProceso, comparador);
        
        
            float producido=0;
            int indice=0;
            while(producido<demanda && !empleadoDisponiblePorProceso.isEmpty() && disponible(procesoUsados,idProceso)){
                EmpleadoXProcesoTurno e=empleadoDisponiblePorProceso.get(indice);
                e.setFo((float)funcionObjetivo(e, idProceso, idGalleta));
                EmpleadoSeleccionado nuevoFinal= new EmpleadoSeleccionado(e,idGalleta);
                nuevoFinal.setFo(e.getFo());
                nuevoFinal.getEmpleadoProceso().getToEmpleado().setAsignado(true);                   
                hallarCostoBeneficio(nuevoFinal,nuevoFinal.getEmpleadoProceso().getToProceso().getIdproceso(),nuevoFinal.getGalleta());                            
                producido=nuevoFinal.getEmpleadoProceso().getProductividad();
                solucionGalleta.add(nuevoFinal);
                empleadoAsignados.add(nuevoFinal);
                empleadoDisponiblePorProceso.remove(indice);
                procesoUsados=actualizarCantidadMaquina(procesoUsados,idProceso);
            }
        return solucionGalleta;
    }
    
    private void actualizarCantidadProcesos(ArrayList<Proceso> procesosUsados, ArrayList<EmpleadoSeleccionado> solucion) {
        
        for(int i=0;i<procesosUsados.size();i++){
            int contador=0;
            for(int k=0;k<solucion.size();k++){
                if(solucion.get(k).getEmpleadoProceso().getToProceso().getIdproceso().equals(procesosUsados.get(i).getIdproceso())){
                    contador++;    
                }
            }
            procesosUsados.get(i).setCantidadmaquina(procesosUsados.get(i).getCantidadmaquina()-contador);
        }
    }

    
    private ArrayList<EmpleadoXProcesoTurno> obtenerOperarios(ArrayList<EmpleadoXProcesoTurno> OperarioMaquina, int idProceso,ArrayList<EmpleadoSeleccionado> listaEmpleado,ArrayList<EmpleadoSeleccionado> listaSolucion) {
        ArrayList<EmpleadoXProcesoTurno> aux=new ArrayList();
        
        for(int i=0; i< OperarioMaquina.size();i++){
            if(OperarioMaquina.get(i).getToProceso().getIdproceso().equals(idProceso) && esFactible1(OperarioMaquina.get(i),listaEmpleado,listaSolucion)){
               aux.add(OperarioMaquina.get(i));
            }
            
        }
        return aux;
    }
    
    private boolean esFactible1(EmpleadoXProcesoTurno nuevoElemento, ArrayList<EmpleadoSeleccionado>listaEmpleado,ArrayList<EmpleadoSeleccionado> solucion2) {
        boolean primero=true;
        boolean segundo=true;
        for(int i=0;i<listaEmpleado.size();i++){
            if(nuevoElemento.getToEmpleado().getIdempleado().equals(listaEmpleado.get(i).getEmpleadoProceso().getToEmpleado().getIdempleado())){
                primero=false;
            }
        }
        
        for(int i=0;i<solucion2.size();i++){
            if(nuevoElemento.getToEmpleado().getIdempleado().equals(solucion2.get(i).getEmpleadoProceso().getToEmpleado().getIdempleado())){
                segundo=false;
            }
        }
        
      
        return primero && segundo;
    }
    
    private float cantidadMateriaProceso(ArrayList<EmpleadoSeleccionado>solucion,int proceso){
        float suma=0;
        for(int i=0;i<solucion.size();i++){
            if(solucion.get(i).getEmpleadoProceso().getToProceso().getIdproceso().equals(proceso)){
                suma+=solucion.get(i).getEmpleadoProceso().getProductividad();
            }
        }
        
        return suma;
    }
    
     private float hallarCantidadMateriaPrima(int idproducto, int idmaterial) {
         for(int i=0;i<listaReceta.size();i++){
             if(listaReceta.get(i).getToProducto().getIdproducto().equals(idproducto) &&
                     listaReceta.get(i).getToProducto1().getIdproducto().equals(idmaterial)){
                     return listaReceta.get(i).getCantidad();
             }
         }
         return 0;
     }
   
    private Producto hallarProductoIntermedio(int idProceso, int idGalleta) {
        
    Producto pmaterial;
       for(int k=0;k<productoProcesoSalida.size();k++){
                    if(productoProcesoSalida.get(k).getToProducto().getIdproducto().equals(idGalleta)
                     && productoProcesoSalida.get(k).getToProceso().getIdproceso().equals(idProceso)){
                        return pmaterial=productoProcesoSalida.get(k).getToProducto1();
                    }
       }
       return null;
    }
                    
  
}
    

